home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / rpc / rpcClient.c < prev    next >
C/C++ Source or Header  |  1991-03-16  |  21KB  |  646 lines

  1. /*
  2.  * rpcClient.c --
  3.  *
  4.  *      The client side of the RPC protocol.  The routines here are in
  5.  *      this file because they synchronize with each other using a master
  6.  *      lock.  RpcDoCall is the send-receive-timeout loop and
  7.  *      RpcClientDispatch is the interrupt time routine that gets packets
  8.  *      and hands them up to RpcDoCall.
  9.  *
  10.  * Copyright 1986 Regents of the University of California
  11.  * All rights reserved.
  12.  */
  13.  
  14. #ifndef lint
  15. static char rcsid[] = "$Header: /sprite/src/kernel/rpc/RCS/rpcClient.c,v 9.10 91/03/15 15:40:57 ouster Exp Locker: mgbaker $ SPRITE (Berkeley)";
  16. #endif /* not lint */
  17.  
  18.  
  19. #include <sprite.h>
  20. #include <stdio.h>
  21. #include <rpc.h>
  22. #include <rpcInt.h>
  23. #include <rpcClient.h>
  24. #include <rpcServer.h>
  25. #include <rpcTrace.h>
  26. #include <dbg.h>
  27. #include <proc.h>
  28. #include <sys.h>
  29.  
  30.  
  31. /*
  32.  * For debugging servers.  We allow client's to retry forever instead
  33.  * of timing out.  This is exported and settable via Fs_Command
  34.  */
  35. Boolean rpc_NoTimeouts = FALSE;
  36.  
  37. /*
  38.  * A histogram is kept of the elapsed time of each different kind of RPC.
  39.  */
  40. Rpc_Histogram *rpcCallTime[RPC_LAST_COMMAND+1];
  41. Boolean rpcCallTiming = FALSE;
  42.  
  43. #ifdef DEBUG
  44. #define DEBUGSIZE 1000
  45. #define INC(ctr) { (ctr) = ((ctr) == DEBUGSIZE-1) ? 0 : (ctr)+1; }
  46. typedef struct {
  47.     RpcClientChannel    *chanPtr;
  48.     char        *action;
  49.     int            pNum;
  50.     int            serverID;
  51.     int            chanNum;
  52.     int            state;
  53. } dbgElem;
  54.  
  55. static dbgElem    dbgArray[DEBUGSIZE];
  56. static int         dbgCtr;
  57.  
  58. #define CHAN_TRACE(zchanPtr, serverID, string) \
  59. { \
  60.     dbgElem *ptr = &dbgArray[dbgCtr]; \
  61.     INC(dbgCtr); \
  62.     ptr->chanPtr = zchanPtr; \
  63.     ptr->action = string; \
  64.     ptr->chanNum = zchanPtr->index; \
  65.     ptr->serverID = serverID; \
  66.     ptr->pNum = Mach_GetProcessorNumber(); \
  67.     ptr->state = zchanPtr->state; \
  68. }
  69.  
  70. #else
  71. #define CHAN_TRACE(zchanPtr, serverID, string)
  72. #endif
  73.  
  74. /* Variables to control nack back-off on client. */
  75. int    rpcNackRetryWait;
  76. int    rpcMaxNackWait;
  77. /*
  78.  * This variable determines whether we use client policy of ramping down
  79.  * channels for neg acks.  The default is to use backoff.
  80.  */
  81. Boolean    rpcChannelNegAcks = FALSE;
  82.  
  83.  
  84. /*
  85.  *----------------------------------------------------------------------
  86.  *
  87.  * RpcDoCall --
  88.  *
  89.  *    The send-receive-timeout loop on the client for a remote procedure call.
  90.  *
  91.  * Results:
  92.  *    The return code from the remote procedure or an error code
  93.  *    related to the RPC protocol, or SUCCESS.
  94.  *
  95.  * Side effects:
  96.  *    The remote procedure call itself.
  97.  *
  98.  *----------------------------------------------------------------------
  99.  */
  100. ReturnStatus
  101. RpcDoCall(serverID, chanPtr, storagePtr, command, srvBootIDPtr, notActivePtr)
  102.     int serverID;        /* The Sprite host that will execute the
  103.                  * service procedure */
  104.     register RpcClientChannel *chanPtr;    /* The channel for the RPC */
  105.     Rpc_Storage *storagePtr;    /* Pointers to caller's buffers */
  106.     int command;        /* Only used to filter trace records */
  107.     unsigned    int *srvBootIDPtr;    /* Return, boot time stamp of server. */
  108.     int *notActivePtr;        /* Return, RPC_NOT_ACTIVE flag from server.
  109.                  * These last two return parameters are later
  110.                  * passed to the recovery module. */
  111. {
  112.     register RpcHdr *rpcHdrPtr;    /* Pointer to received message header */
  113.     register RpcConst *constPtr;/* Timeout parameter block */
  114.     register ReturnStatus error;/* General error return status */
  115.     register unsigned int wait;    /* Wait interval for timeouts */
  116.     int numAcks;        /* Count of acks received.  Used to catch the
  117.                  * case where the server process hangs and
  118.                  * the server dispatcher acks us forever */
  119.     register int numTries;    /* Number of times we sent the message while
  120.                  * getting no reply. */
  121.     register unsigned int lastFragMask = 0;    /* Previous state of our
  122.                          * fragment reassembly */
  123.     Boolean    seemsHung = FALSE;    /* Used to control warning msgs */
  124.  
  125.     /*
  126.      * This code is locked with MASTER_LOCK in order to synchronize
  127.      * with the RpcClientDispatch routine.  Inside the critical
  128.      * section we sleep on the channel's wait condition to which
  129.      * RpcClientDispatch broadcasts when it gets input.  Furthermore,
  130.      * we place a call back procedure in the timer queue that will
  131.      * also notify that condition upon timeout.
  132.      */
  133.     MASTER_LOCK(&chanPtr->mutex);
  134.  
  135.     /*
  136.      * Send the request off to the server.  We update the server hint from
  137.      * the channel's return message header.  ie. take the last server
  138.      * hint received from the server.
  139.      */
  140.  
  141.     *srvBootIDPtr = 0;
  142.     rpcCltStat.requests++;
  143.     chanPtr->requestRpcHdr.serverHint =    chanPtr->replyRpcHdr.serverHint;
  144.     chanPtr->state |= CHAN_WAITING;
  145.     error = RpcOutput(serverID, (RpcHdr *) &chanPtr->requestRpcHdr,
  146.               &chanPtr->request, chanPtr->fragment,
  147.               (unsigned int) (chanPtr->fragsDelivered),
  148.               &chanPtr->mutex);
  149.     /*
  150.      * Set up the initial wait interval.  The wait could depend on
  151.      * characteristics of the RPC, or of the other host.
  152.      * For now we just wait longer if the packet will be fragmented.
  153.      */
  154.     constPtr = chanPtr->constPtr;
  155.     if ((storagePtr->requestDataSize + storagePtr->requestParamSize >
  156.         RPC_MAX_FRAG_SIZE) ||
  157.     (storagePtr->replyDataSize + storagePtr->replyParamSize >
  158.         RPC_MAX_FRAG_SIZE)) {
  159.     wait = constPtr->fragRetryWait;
  160.     } else {
  161.     wait = constPtr->retryWait;
  162.     }
  163.  
  164.     /*
  165.      * Loop waiting for input and re-sending if need be.  As well as
  166.      * getting a reply from the server we screen out junk and react to
  167.      * explicit acks.  This times out after a number of times around the
  168.      * loop with no input.
  169.      */
  170.     numTries = 0;
  171.     numAcks = 0;
  172.     do {
  173.  
  174.     /*
  175.      * Wait until we get a poke from the timeout routine or there
  176.      * is input available.  Input may have arrived before we get
  177.      * here because the channel mutex is released while Rpc_Output
  178.      * waits for the packet to be sent by the network interface.
  179.      */
  180.     if (! (chanPtr->state & CHAN_INPUT)) {
  181.         chanPtr->timeoutItem.routine = Rpc_Timeout;
  182.         chanPtr->timeoutItem.interval = wait;
  183.         chanPtr->timeoutItem.clientData = (ClientData)chanPtr;
  184.         chanPtr->state |= CHAN_TIMEOUT | CHAN_WAITING;
  185.         CHAN_TRACE(chanPtr, serverID, "about to schedule");
  186.         Timer_ScheduleRoutine(&chanPtr->timeoutItem, TRUE);
  187.         do {
  188.         /*
  189.          * Wait ignoring signals.
  190.          */
  191.         Sync_MasterWait(&chanPtr->waitCondition,
  192.                 &chanPtr->mutex, FALSE);
  193.         } while (((chanPtr->state & CHAN_INPUT) == 0) &&
  194.              (chanPtr->state & CHAN_TIMEOUT));
  195.         CHAN_TRACE(chanPtr, serverID, "woken up");
  196.     }
  197.     if (chanPtr->state & CHAN_INPUT) {
  198.         /*
  199.          * Got some input.  The dispatch routine has copied the
  200.          * packet into the areas refered to by the reply BufferSet.
  201.          *
  202.          * NB: We have to completely process this message before we
  203.          * can accept another message on this channel.  There is no
  204.          * mechanism to queue messages.
  205.          */
  206.         chanPtr->state &= ~CHAN_INPUT;
  207.         rpcHdrPtr = &chanPtr->replyRpcHdr;
  208.  
  209.         /*
  210.          * Pick off the boot timestamp and active state of the server so
  211.          * the recovery module can pay attention to traffic.
  212.          */
  213.         *notActivePtr = rpcHdrPtr->flags & RPC_NOT_ACTIVE;
  214.         *srvBootIDPtr = rpcHdrPtr->bootID;
  215. #ifdef TIMESTAMP
  216.         RPC_TRACE(rpcHdrPtr, RPC_CLIENT_D, "input");
  217. #endif /* TIMESTAMP */
  218.         if (rpcHdrPtr->ID != chanPtr->requestRpcHdr.ID) {
  219.         /*
  220.          * Note old message.
  221.          */
  222.         rpcCltStat.oldInputs++;
  223.  
  224.         } else if (rpcHdrPtr->flags & RPC_NACK) {
  225.         /*
  226.          * NOTE: for now we must handle a NACK before an ACK because
  227.          * I'm OR'ing in an ACK with the NACK so that old kernels on
  228.          * clients won't freak if they receive a NACK.  This backwards
  229.          * compatibility should be removed later.  The changes that go
  230.          * with it are setting the serverHint in RpcSrvInitHdr() and
  231.          * the OR'ing itself of the ACK with the NACK in rpcServer.c.
  232.          */
  233.         rpcCltStat.nacks++;
  234.         /*
  235.          * Try out different nack-handling policies.  
  236.          * We can either back off as in an ACK, or try to ramp
  237.          * down the number of channels.
  238.          */
  239.         if (serverID != RPC_BROADCAST_SERVER_ID) {
  240.             numTries = 0;
  241.             if (!rpcChannelNegAcks) {
  242.             if (wait < rpcNackRetryWait) {
  243.                 wait = rpcNackRetryWait;
  244.             } else {
  245.                 Net_HostPrint(serverID,
  246.                 "Client backing off again from negative ack.\n");
  247.                 wait *= 2;
  248.                 rpcCltStat.reNacks++;
  249.             }
  250.             if (wait > rpcMaxNackWait) {
  251.                 Net_HostPrint(serverID,
  252.                 "Client setting max backoff from negative ack.\n");
  253.                 wait = rpcMaxNackWait;
  254.                 rpcCltStat.maxNacks++;
  255.             }
  256.             } else {
  257.             /* Return error to cause ramping down of channels. */
  258.             error = RPC_NACK_ERROR; 
  259.             }
  260.         }
  261.         } else if (rpcHdrPtr->flags & RPC_REPLY) {
  262.         /*
  263.          * Our reply, check for an error code and break from the
  264.          * receive loop.  The command field is overloaded with the
  265.          * return error code.
  266.          */
  267.         if (rpcHdrPtr->flags & RPC_ERROR) {
  268.             error = (ReturnStatus)rpcHdrPtr->command;
  269.             if (error == 0) {
  270.             rpcCltStat.nullErrors++;
  271.             error = RPC_NULL_ERROR;
  272.             } else {
  273.             rpcCltStat.errors++;
  274.             }
  275.         } else {
  276.             rpcCltStat.replies++;
  277.         }
  278.         /*
  279.          * Copy back the return buffer size (it's set by ClientDispatch)
  280.          * to reflect what really came back.
  281.          */
  282.         storagePtr->replyDataSize = chanPtr->actualDataSize;
  283.         storagePtr->replyParamSize = chanPtr->actualParamSize;
  284.         break;
  285.         } else if (rpcHdrPtr->flags & RPC_ACK) {
  286.         numAcks++;
  287.         rpcCltStat.acks++;
  288.         if (numAcks <= constPtr->maxAcks) {
  289.             /*
  290.              * An ack from the server indicating that a server
  291.              * process is working on our request.  We increase
  292.              * our waiting time to decrease the change that we'll
  293.              * timeout again before receiving the reply.
  294.              * NOTE: We don't pay attention to acks if we are
  295.              * broadcasting.  This makes the broadcaster too vulnerable
  296.              * to errant servers.  In particular, diskless clients
  297.              * often wedge trying to handle a prefix request, send
  298.              * the real server a lot of acks, and slow it's boot down.
  299.              */
  300.             if (serverID != RPC_BROADCAST_SERVER_ID) {
  301.             numTries = 0;
  302.             wait *= 2;
  303.             if (wait > constPtr->maxAckWait) {
  304.                 wait = constPtr->maxAckWait;
  305.             }
  306.             }
  307.         } else {
  308.             char name[100];
  309.             /*
  310.              * Too many acks.  It is very likely that the server
  311.              * process is hung on some lock.  We hang too in
  312.              * order to facilitate debugging.
  313.              */
  314.             rpcCltStat.tooManyAcks++;
  315.             if (!seemsHung) {
  316.             Net_SpriteIDToName(serverID, 100, name);
  317.             if (name == (char *)NIL) {
  318.                 printf("RpcDoCall: <%s> RPC to host <%d> is hung\n",
  319.                 rpcService[command].name, serverID);
  320.             } else {
  321.                 printf("RpcDoCall: <%s> RPC to %s is hung\n",
  322.                 rpcService[command].name, name);
  323.             }
  324.             seemsHung = TRUE;
  325.             }
  326.             numAcks = 0;
  327.         }
  328.         } else {
  329.         /*
  330.          * Unexpected kind of input
  331.          */
  332.         rpcCltStat.badInput++;
  333.         printf("Warning: Rpc_Call: Unexpected input.\n");
  334.         error = RPC_INTERNAL_ERROR;
  335.         }
  336.     } else {
  337.         /*
  338.          * Have not received a complete message yet.  Update the
  339.          * server hint and then re-send the request or send a partial
  340.          * acknowledgment.
  341.          */
  342.         chanPtr->requestRpcHdr.serverHint =
  343.         chanPtr->replyRpcHdr.serverHint;
  344.         rpcCltStat.timeouts++;
  345.         /*
  346.          * Back off upon timeout because we may be talking to a slow host
  347.          */
  348.         wait *= 2;
  349.         if (wait > constPtr->maxTimeoutWait) {
  350.         wait = constPtr->maxTimeoutWait;
  351.         }
  352.         if ((chanPtr->state & CHAN_FRAGMENTING) == 0) {
  353.         /*
  354.          * Not receiving fragments.  Check for timeout, and resend
  355.          * the request.
  356.          */
  357.         numTries++;
  358.         if (numTries < constPtr->maxTries ||
  359.             (rpc_NoTimeouts && serverID != RPC_BROADCAST_SERVER_ID)) {
  360.             rpcCltStat.resends++;
  361.             chanPtr->requestRpcHdr.flags |= RPC_PLSACK;
  362.             error = RpcOutput(serverID, 
  363.                       (RpcHdr *) &chanPtr->requestRpcHdr,
  364.                       &chanPtr->request, chanPtr->fragment,
  365.                       (unsigned int) (chanPtr->fragsDelivered),
  366.                       &chanPtr->mutex);
  367.         } else {
  368.             rpcCltStat.aborts++;
  369.             error = RPC_TIMEOUT;
  370.         }
  371.         } else {
  372.         /*
  373.          * We are getting a fragmented response.  The client dispatcher
  374.          * has set the fragsReceived field to reflect the state
  375.          * of fragment reassembly.  We check that and will abort
  376.          * if we timeout too many times with no new fragments.
  377.          * Otherwise we return a partial acknowledgment.
  378.          */
  379.         if (lastFragMask < chanPtr->fragsReceived) {
  380.             lastFragMask = chanPtr->fragsReceived;
  381.             numTries = 0;
  382.         } else {
  383.             numTries++;
  384.         }
  385.         if (numTries >= constPtr->maxTries &&
  386.             (!rpc_NoTimeouts||(serverID == RPC_BROADCAST_SERVER_ID))) {
  387.             rpcCltStat.aborts++;
  388.             error = RPC_TIMEOUT;
  389.         } else {
  390.             chanPtr->requestRpcHdr.flags = RPC_SERVER |RPC_ACK |
  391.                             RPC_LASTFRAG;
  392.             chanPtr->requestRpcHdr.fragMask = chanPtr->fragsReceived;
  393.             rpcCltStat.sentPartial++;
  394.             error = RpcOutput(serverID, 
  395.                       (RpcHdr *) &chanPtr->requestRpcHdr,
  396.                       &chanPtr->request, chanPtr->fragment,
  397.                       (unsigned int) (chanPtr->fragsDelivered),
  398.                       &chanPtr->mutex);
  399.         }
  400.         }
  401.     }
  402.     } while (error == SUCCESS);
  403.     chanPtr->state &= ~CHAN_WAITING;
  404.     if (seemsHung) {
  405.     if (error == SUCCESS) {
  406.         printf("<%s> RPC ok\n", rpcService[command].name);
  407.     } else {
  408.         printf("<%s> RPC exit 0x%x\n", rpcService[command].name, error);
  409.     }
  410.     }
  411.     MASTER_UNLOCK(&chanPtr->mutex);
  412.     return(error);
  413. }
  414.  
  415. /*
  416.  *----------------------------------------------------------------------
  417.  *
  418.  * RpcClientDispatch --
  419.  *
  420.  *      Dispatch a message to a client channel.  The channel has buffer
  421.  *      space for the packet header and also specifies the buffer areas
  422.  *      for the RPC return parameters and data.  We notify the owner of
  423.  *      the channel that is has input via the condition variable in the
  424.  *      channel.
  425.  *
  426.  * Sprite Id:
  427.  *    This routine has the side effect of initializing the Sprite ID
  428.  *    of the host from information in the RPC packet header.  This is
  429.  *    for diskless clients of the filesystem that have no other way
  430.  *    to determine their Sprite ID.  The routine RpcValidateClient
  431.  *    on the server side initializes the clientID field for us.
  432.  *
  433.  * Results:
  434.  *    None.
  435.  *
  436.  * Side effects:
  437.  *    The message is copied into the buffers specified by the channel
  438.  *    and the channel is notified of input.
  439.  *
  440.  *----------------------------------------------------------------------
  441.  */
  442. void
  443. RpcClientDispatch(chanPtr, rpcHdrPtr)
  444.     register RpcClientChannel *chanPtr;    /* The channel the packet is for */
  445.     register RpcHdr *rpcHdrPtr;        /* The Rpc header as it sits in the
  446.                      * network module's buffer.  The data
  447.                      * in the message follows this. */
  448. {
  449.     register int size;    /* The amount of data in the message */
  450.     /*
  451.      * Acquire the channel mutex for multiprocessor synchronization.
  452.      * Deadlock occurs here when doing RPCs to oneself and the client
  453.      * resends and then the server acknowledges.
  454.      */
  455. #if (MACH_MAX_NUM_PROCESSORS == 1) /* uniprocessor implementation */
  456.     if (chanPtr->mutex.value != 0) {
  457.     printf("Warning:  Rpc to myself?\n");
  458.     return;
  459.     } else {
  460.     MASTER_LOCK(&chanPtr->mutex);
  461.     }
  462. #else    /* Multiprocessor implementation. */
  463.     MASTER_LOCK(&chanPtr->mutex);
  464. #endif
  465.     
  466.     /*
  467.      * Discover our own Sprite ID from the packet header.
  468.      */
  469.     if (rpc_SpriteID == 0) {
  470.     rpc_SpriteID = rpcHdrPtr->clientID;
  471.     printf("RPC setting SpriteID to %d.\n", rpc_SpriteID);
  472.     } else if (rpc_SpriteID != rpcHdrPtr->clientID) {
  473.     printf("RpcClientDispatch: clientID changed from (%d) to (%d).\n",
  474.                        rpc_SpriteID, rpcHdrPtr->clientID);
  475.     }
  476.  
  477.     /*
  478.      * See if this is a close request from the server - the server host is
  479.      * trying to recycle the server process that is bound to this
  480.      * channel.  If the channel is not busy now it implies we have completed
  481.      * the RPC the server is inquiring about.  We return an ack to the
  482.      * server and unbind the server process from us.  During this the
  483.      * channel is marked busy so that while we are returning the ack,
  484.      * another process doesn't come along, allocate the channel, and try
  485.      * to use the same buffers as us.
  486.      */
  487.     if (rpcHdrPtr->flags & RPC_CLOSE) {
  488.     RpcChanClose(chanPtr, rpcHdrPtr);
  489.     goto unlock;
  490.     }
  491.  
  492.     /*
  493.      * Verify the transaction Id.  Doing this now after checking for
  494.      * close messages means we still ack close requests even if
  495.      * we have already recycled the channel.
  496.      */
  497.     if (rpcHdrPtr->ID != chanPtr->requestRpcHdr.ID) {
  498.     rpcCltStat.badId++;
  499.     goto unlock;
  500.     }
  501.  
  502.     /*
  503.      * Filter out partial acks.
  504.      */
  505.     if ((rpcHdrPtr->fragMask != 0) && (rpcHdrPtr->flags & RPC_ACK)) {
  506.     if (chanPtr->fragsDelivered != rpcHdrPtr->fragMask) {
  507.         /*
  508.          * Because we may get several partial acks, we just update
  509.          * fragsDelivered so the next resend is smarter.  Eventually
  510.          * we'll get all the fragments delivered and then these
  511.          * acks will get passed up to RpcDoCall().
  512.          */
  513.         chanPtr->fragsDelivered = rpcHdrPtr->fragMask;
  514.         rpcCltStat.recvPartial++;
  515.         goto unlock;
  516.     }
  517.     /*
  518.      * Apparently we've gotten everything through to the
  519.      * server.  Our last transmission was a keep-alive
  520.      * of just the last fragment.  We FALL THROUGH to
  521.      * pass the server's ack up to the process level, RpcDoCall();
  522.      */
  523.     }
  524.  
  525.     /*
  526.      * See if the channel is available for input.  Currently there
  527.      * is no queueing of packets so we drop this packet if the process
  528.      * is still working on the last packet it got.
  529.      */
  530.     if ((chanPtr->state & CHAN_WAITING) == 0) {
  531.     rpcCltStat.chanBusy++;
  532.     goto unlock;
  533.     }
  534.     /*
  535.      * Note for RpcDoCall the actual size of the returned information.
  536.      */
  537.     size = rpcHdrPtr->paramSize + rpcHdrPtr->paramOffset;
  538.     if (chanPtr->actualParamSize < size) {
  539.     chanPtr->actualParamSize = size;
  540.     }
  541.     size = rpcHdrPtr->dataSize + rpcHdrPtr->dataOffset;
  542.     if (chanPtr->actualDataSize < size) {
  543.     chanPtr->actualDataSize = size;
  544.     }
  545.  
  546.     if (rpcHdrPtr->numFrags != 0) {
  547.     if ((chanPtr->state & CHAN_FRAGMENTING) == 0) {
  548.         /*
  549.          * The first fragment of a fragmented reply.
  550.          */
  551.         RpcScatter(rpcHdrPtr, &chanPtr->reply);
  552.         chanPtr->fragsReceived = rpcHdrPtr->fragMask;
  553.         chanPtr->state |= CHAN_FRAGMENTING;
  554.         goto unlock;
  555.     } else if (chanPtr->fragsReceived & rpcHdrPtr->fragMask) {
  556.         /*
  557.          * Duplicate fragment.
  558.          */
  559.         rpcCltStat.dupFrag++;
  560.         goto unlock;
  561.     } else {
  562.         /*
  563.          * More fragments.
  564.          */
  565.         RpcScatter(rpcHdrPtr, &chanPtr->reply);
  566.         chanPtr->fragsReceived |= rpcHdrPtr->fragMask;
  567.         if (chanPtr->fragsReceived !=
  568.            rpcCompleteMask[rpcHdrPtr->numFrags]) {
  569.         goto unlock;
  570.         } else {
  571.         /*
  572.          * Now the packet is complete.
  573.          */
  574.         chanPtr->state &= ~CHAN_FRAGMENTING;
  575.         }
  576.     }
  577.     } else {
  578.     /*
  579.      * Unfragmented message.
  580.      * Copy the complete message out of the network's buffers.
  581.      */
  582.     RpcScatter(rpcHdrPtr, &chanPtr->reply);
  583.     }
  584.     
  585.     /*
  586.      * Remove the channel from the timeout queue and
  587.      * notify the waiting channel that it has input.
  588.      */
  589.     chanPtr->state &= ~CHAN_WAITING;
  590.     chanPtr->state |= CHAN_INPUT;
  591.  
  592.     if (chanPtr->state & CHAN_TIMEOUT) {
  593.     chanPtr->state &= ~CHAN_TIMEOUT;
  594.     CHAN_TRACE(chanPtr, chanPtr->serverID, "about to deschedule");
  595.     (void)Timer_DescheduleRoutine(&chanPtr->timeoutItem);
  596.     }
  597.     Sync_MasterBroadcast(&chanPtr->waitCondition);
  598.  
  599. unlock:
  600. #ifdef TIMESTAMP
  601.     RPC_TRACE(rpcHdrPtr, RPC_CLIENT_a, "client");
  602. #endif /* TIMESTAMP */
  603.  
  604.     MASTER_UNLOCK(&chanPtr->mutex);
  605. }
  606.  
  607. /*
  608.  *----------------------------------------------------------------------
  609.  *
  610.  * Rpc_Timeout --
  611.  *
  612.  *    Called when a channel times out.  This notifies the waiting condition
  613.  *    of the channel so the process can wake up and take action upon
  614.  *    the timeout.  The mutex on the channel is aquired for multiprocessor
  615.  *    synchronization.
  616.  *
  617.  * Results:
  618.  *    None.
  619.  *
  620.  * Side effects:
  621.  *    The channel contition is notified.
  622.  *
  623.  *----------------------------------------------------------------------
  624.  */
  625. /*ARGSUSED*/
  626. void
  627. Rpc_Timeout(time, data)
  628.     Timer_Ticks time;    /* The time we timed out at. */
  629.     ClientData data;    /* Our private data is the channel pointer */
  630. {
  631.     RpcClientChannel *chanPtr;    /* The channel to notify */
  632.  
  633.     chanPtr = (RpcClientChannel *)data;
  634.  
  635.     /*
  636.      * This is called from the timeout queue at interrupt time.
  637.      * We acquire the master lock (as a formality in a uniprocessor)
  638.      * and use the form of broadcast designed for master locks.
  639.      */
  640.     MASTER_LOCK(&chanPtr->mutex);
  641.     chanPtr->state &= ~CHAN_TIMEOUT;
  642.     CHAN_TRACE(chanPtr, chanPtr->serverID, "Timeout");
  643.     Sync_MasterBroadcast(&chanPtr->waitCondition);
  644.     MASTER_UNLOCK(&chanPtr->mutex);
  645. }
  646.